<?php

Raise::load('core.RaiseDataType');

/**
 * IpAddress class
 * defines and contain IPv4 address
 *
 * @author Sam-Mauris Yong <hellclanner at live dot com>
 * @license http://www.opensource.org/licenses/bsd-license New BSD License
 * @package Raise.Core.DataStructure
 * @since 1.2
 */
class IpAddress extends RaiseDataType {

    /**
     * First octet of the IPv4 address
     * @var integer
     */
    private $octetone;

    /**
     * Second octet of the IPv4 address
     * @var integer
     */
    private $octettwo;

    /**
     * Third octet of the IPv4 address
     * @var integer
     */
    private $octetthree;

    /**
     * Last octet of the IPv4 address
     * @var integer
     */
    private $octetfour;

    /**
     * Create a new IpAddress
     * @param string|integer,... $ipstr the IP address to input
     */
    public function __construct($ipstr) {
        $iargs =  func_get_args();
        $args = call_user_func_array(array('IpAddress', 'convertArgs'), $iargs);
        unset($iargs);
        $this->octetone = $args[0];
        $this->octettwo = $args[1];
        $this->octetthree = $args[2];
        $this->octetfour = $args[3];
    }

    /**
     * Convert either a string or numeric arguments into the 4 octets
     * @param string|integer,...
     * @return array
     * @static
     */
    private static function convertArgs() {
        $ret = array();
        $args = func_get_args();
        $n = func_num_args();
        if ($n == 4) {
            $ret[] = $args[0];
            $ret[] = $args[1];
            $ret[] = $args[2];
            $ret[] = $args[3];
        } elseif ($n == 1) {
            $ap = explode('.', $args[0]);
            $ret[] = $ap[0];
            $ret[] = $ap[1];
            $ret[] = $ap[2];
            $ret[] = $ap[3];
        }
        return $ret;
    }

    /**
     * Mask an IpAddress with another
     * @param string|integer,... $mask the IP address to input
     */
    public function mask($mask) {
        $fargs = func_get_args();
        $args = call_user_func_array(array('IpAddress', 'convertArgs'), $fargs);
        return new IpAddress($this->octetone & $args[0],
                $this->octettwo & $args[1],
                $this->octetthree & $args[2],
                $this->octetfour & $args[3]);
    }

    /**
     * Return the IpAddress as an IPv4 string
     * Convert a string containing an (IPv4) Internet Protocol dotted address into a proper address
     * @return bool|integer
     * @link http://php.net/ip2long
     */
    public function toLong(){
        return ip2long($this->__toString());
    }

    /**
     * Convert an (IPv4) Internet network address into a string in Internet standard dotted format
     * @param integer $long
     * @return IpAddress 
     */
    public static function fromLong($long){
        return new IpAddress(long2ip($long));
    }

    /**
     * Get the IpAdrress in the form of an 1D array
     * @return array
     */
    public function toArray() {
        return array($this->octetone, $this->octettwo, $this->octetthree, $this->octetfour);
    }

    /**
     * Returns the IpAddress as an IPv4 string
     * @return string
     */
    function __toString() {
        return $this->octetone . '.' . $this->octettwo .
        '.' . $this->octetthree . '.' . $this->octetfour;
    }

    /**
     * Compare whether both IpAddress values are equal or not
     * @param IpAddress $c
     * @return boolean
     */
    public function equals($c){
        return $this->__toString() == $c->__toString();
    }

    /**
     * Check whether the IpAddress matches a mask
     * @param string $mask The mask to match the IpAddress. Use * to mark variable octets.
     * @return boolean TRUE if the IpAddress matches the mask, FALSE otherwise
     */
    public function matchMask($mask){
        $mo = explode('.', $mask);
        if(($mo[0] == '*' || $mo[0] == $this->octetone) && ($mo[1] == '*' || $mo[1] == $this->octettwo) && ($mo[2] == '*' || $mo[2] == $this->octetthree) && ($mo[3] == '*' || $mo[3] == $this->octetfour)){
            return true;
        }
        return false;
    }
    
}
